//--------------------------------------------------------------------------------
// This file is part of the Windows Workflow Foundation Sample Code
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// This source code is intended only as a supplement to Microsoft
// Development Tools and/or on-line documentation.  See these other
// materials for detailed information regarding Microsoft code samples.
// 
// THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//--------------------------------------------------------------------------------

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.Runtime;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.Serialization;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using Microsoft.Samples.Workflow.UI.Design;
using System.Drawing.Design;
using System.Diagnostics;

namespace Microsoft.Samples.Workflow.UI
{
    [Designer(typeof(InteractionGroupDesigner))]
    [ToolboxItem(typeof(InteractionGroupToolboxItem))]
    [ToolboxBitmap(typeof(InteractionGroupActivity), "Resources.InteractionGroupActivity.png")]
    [ActivityValidator(typeof(InteractionGroupActivityValidator))]
    public class InteractionGroupActivity : InteractionBaseActivity, IActivityEventListener<ActivityExecutionStatusChangedEventArgs>
    {
        public static readonly DependencyProperty UntilConditionProperty = DependencyProperty.Register("UntilCondition", typeof(ActivityCondition), typeof(InteractionGroupActivity));

        public InteractionGroupActivity()
        {
            this.SetValue(ReceiveInputProperty, true);
            this.SetValue(ActivityInputTypeProperty, typeof(string));
        }

        public InteractionGroupActivity(string name)
            : base(name)
        {
            this.SetValue(ReceiveInputProperty, true);
            this.SetValue(ActivityInputTypeProperty, typeof(string));
        }

        [SRCategory(SR.Interaction)]
        [SRDescription(SR.UntilConditionDescription)]
        public ActivityCondition UntilCondition
        {
            get
            {
                return base.GetValue(UntilConditionProperty) as ActivityCondition;
            }
            set
            {
                base.SetValue(UntilConditionProperty, value);
            }
        }

        protected override ActivityExecutionStatus OnExecute(ActivityExecutionContext executionContext)
        {
            if (executionContext == null)
            {
                throw new ArgumentNullException("executionContext");
            }

            if (this.EnabledActivities.Count == 0)
            {
                return ActivityExecutionStatus.Closed;
            }

            string interactionActivityName = this.ActivityInput as string;
            foreach (Activity childActivity in this.EnabledActivities)
            {
                Activity foundActivity = null;
                if (childActivity is InteractionActivity && childActivity.QualifiedName == interactionActivityName)
                {
                    foundActivity = childActivity;
                }
                else if (childActivity is Navigator)
                {
                    foundActivity = Helpers.GetImmediateChildByName(childActivity, interactionActivityName);
                }

                if (foundActivity != null)
                {
                    if (childActivity.ExecutionStatus == ActivityExecutionStatus.Initialized)
                    {
                        childActivity.RegisterForStatusChange(Activity.ClosedEvent, this);
                        executionContext.ExecuteActivity(childActivity);
                    }
                    else if (childActivity.ExecutionStatus == ActivityExecutionStatus.Executing)
                    {
                        Activity rootActivity = Helpers.GetRootActivity(this);
                        InteractionContext currentInteraction = null;
                        if (childActivity is InteractionActivity)
                        {
                            currentInteraction = ((InteractionActivity)childActivity).GetInteractionContext();
                        }
                        else if (childActivity is Navigator)
                        {
                            currentInteraction = Helpers.GetInteractionContextForNavigator(childActivity as Navigator);
                        }
                        else
                        {
                            Debug.Assert(false, "child of InteractionGroup must be either InteractionActivity or Navigator");
                        }
                        InteractionCommand interactionCommand = rootActivity.GetValue(InteractionCommandProperty) as InteractionCommand;
                        if (interactionCommand != null)
                        {
                            interactionCommand.NextInteraction = currentInteraction;
                            if (childActivity is Navigator)
                            {
                                Activity currentActivityInChildNavigator = ((Navigator)childActivity).Current;
                                Guid currentContextID = (Guid)currentActivityInChildNavigator.GetValue(Activity.ActivityContextGuidProperty);
                                Navigator.RemoveHistory(currentContextID, currentActivityInChildNavigator, true);
                                Navigator.AddHistory(currentActivityInChildNavigator);
                            }
                        }
                    }
                }
            }

            return ActivityExecutionStatus.Executing;
        }

        protected override ActivityExecutionStatus OnCancel(ActivityExecutionContext executionContext)
        {
            if (executionContext == null)
            {
                throw new ArgumentNullException("executionContext");
            }

            bool canCloseNow = true;

            for (int i = 0; i < this.EnabledActivities.Count; ++i)
            {
                Activity childActivity = this.EnabledActivities[i];

                if (childActivity.ExecutionStatus == ActivityExecutionStatus.Executing)
                {
                    executionContext.CancelActivity(childActivity);
                    canCloseNow = false;
                }
                else if (childActivity.ExecutionStatus == ActivityExecutionStatus.Canceling || childActivity.ExecutionStatus == ActivityExecutionStatus.Faulting)
                {
                    canCloseNow = false;
                }
            }

            return canCloseNow ? ActivityExecutionStatus.Closed : ActivityExecutionStatus.Canceling;
        }

        protected internal override InteractionContext GetInteractionContext()
        {
            InteractionGroupContext interactionContext = new InteractionGroupContext(new Bookmark(this.QualifiedName, this.InteractionId), this.RequiredPermission, this.Error);
            interactionContext.ActiveChildContexts = Helpers.GetActiveChildContexts(this).AsReadOnly();
            interactionContext.AvailableChildContexts = Helpers.GetAvailableChildContexts(this).AsReadOnly();

            return interactionContext;
        }

        protected internal override void InitializePermission(Permission ownerPermission)
        {
            base.InitializePermission(ownerPermission);

            foreach (Activity child in this.EnabledActivities)
            {
                if (child is InteractionActivity)
                {
                    ((InteractionActivity)child).InitializePermission(ownerPermission);
                }
                else if (child is Navigator && ((Navigator)child).OwnerPermission == null)
                {
                    ((Navigator)child).OwnerPermission = ownerPermission;
                }
            }
        }

        void IActivityEventListener<ActivityExecutionStatusChangedEventArgs>.OnEvent(Object sender, ActivityExecutionStatusChangedEventArgs e)
        {
            if (sender == null)
            {
                throw new ArgumentNullException("sender");
            }
            if (e == null)
            {
                throw new ArgumentNullException("e");
            }

            ActivityExecutionContext context = sender as ActivityExecutionContext;
            if (context == null)
            {
                throw new ArgumentException(SR.GetString(SR.Error_InvalidParameterType, "sender", typeof(ActivityExecutionContext).FullName));
            }

            e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, this);
            InteractionGroupActivity interactionGroup = context.Activity as InteractionGroupActivity;
            if (interactionGroup == null)
            {
                throw new ArgumentException(SR.GetString(SR.Error_InvalidParameterType, "context.Activity", typeof(InteractionGroupActivity).FullName));
            }

            if (interactionGroup.ExecutionStatus == ActivityExecutionStatus.Canceling)
            {
                context.CloseActivity();
            }
            else if (interactionGroup.ExecutionStatus == ActivityExecutionStatus.Executing)
            {
                if (CanCloseNow(context))
                {
                    context.CloseActivity();
                }
                else
                {
                    Activity rootActivity = Helpers.GetRootActivity(this);
                    InteractionContext currentInteraction = this.GetInteractionContext();
                    InteractionCommand interactionCommand = rootActivity.GetValue(InteractionCommandProperty) as InteractionCommand;
                    if (interactionCommand != null)
                    {
                        interactionCommand.NextInteraction = currentInteraction;
                    }
                }
            }
        }

        protected override void OnWorkflowChangesCompleted(ActivityExecutionContext executionContext)
        {
            base.OnWorkflowChangesCompleted(executionContext);

            if (this.ExecutionStatus == ActivityExecutionStatus.Executing)
            {
                if (CanCloseNow(executionContext))
                {
                    executionContext.CloseActivity();
                }
            }
        }

        bool CanCloseNow(ActivityExecutionContext executionContext)
        {
            bool canCloseNow = true;
            if (this.UntilCondition != null)
            {
                canCloseNow = this.UntilCondition.Evaluate(this, executionContext);
                if (canCloseNow)
                {
                    foreach (Activity childActivity in this.EnabledActivities)
                    {
                        if (childActivity.ExecutionStatus == ActivityExecutionStatus.Executing)
                        {
                            executionContext.CancelActivity(childActivity);
                            canCloseNow = false;
                        }
                    }
                }
            }
            else
            {
                foreach (Activity childActivity in this.EnabledActivities)
                {
                    if (childActivity.ExecutionStatus != ActivityExecutionStatus.Closed)
                    {
                        canCloseNow = false;
                        break;
                    }
                }
            }

            return canCloseNow;
        }
    }
}
